/*
 * BAT_Builder.c
 *
 * Builds a BAT_GeneTab object out of a set of features.
 *
 * Bob Zimmermann <rpz@cse.wustl.edu> Totally free.
 */

#include "BAT_Builder.h"

BAT_Builder *
BAT_Builder_new()
{
  BAT_Builder *b;

  b = malloc(sizeof(BAT_Builder));
  b->feats =
    darray_new(20, darray_ops_copy(&BAT_Owner_Ops[Free_Feature_Allocator]));

  return b;
}

void
BAT_Builder_delete(BAT_Builder * b, int befrei)
{
  if (b->feats != NULL)
    darray_delete(b->feats, 1);

  if (befrei)
    free(b);
}

void
BAT_Builder_add_features_from_parser(BAT_Builder * b, BAT_Parser * p)
{
  BAT_Free_Feature **feats;
  da_pos_t n_feats;

  feats = BAT_Parser_claim_features(p, &n_feats);
  BAT_Builder_add_features(b, feats, n_feats);
}

void
BAT_Builder_add_features(BAT_Builder * b, BAT_Free_Feature ** feats,
			 da_pos_t n_feats)
{
  da_pos_t i;

  for (i = 0; i < n_feats; i++)
    darray_add(b->feats, feats[i]);
  free(feats);
}

BAT_GeneTab *
BAT_Builder_build_gene_table(BAT_Builder * b)
{
  BAT_GeneTab *gt;
  BAT_Gene *gene;
  BAT_Transcript *tx;
  BAT_Free_Feature **ffeats, *ffeat;
  BAT_Feature *feat;
  darray_t *gene_groups, *gene_group;
  da_pos_t n_ggs, gg, n_fs, f;
  char *id;

  gt = BAT_GeneTab_new();

  darray_sort(b->feats, BAT_Free_Feature_gid_cmp);
  ffeats = (BAT_Free_Feature **) darray_get_array(b->feats);
  n_fs = darray_size(b->feats);

  gene_groups = darray_new(n_fs / 10, darray_ops_copy(&darray_ops_ops));
  for (f = 0; f < n_fs;) {
    gene_group =
      darray_new(5, darray_ops_copy(&BAT_Passive_Ops[Free_Feature_Allocator]));
    id = BAT_Util_copy_string(BAT_Free_Feature_get_gene_id(ffeats[f]));
    for (; f < n_fs && !strcmp(id, BAT_Free_Feature_get_gene_id(ffeats[f]));
	 f++)
      darray_add(gene_group, ffeats[f]);
    darray_add(gene_groups, gene_group);
    free(id);
  }

  n_ggs = darray_size(gene_groups);
  for (gg = 0; gg < n_ggs; gg++) {
    gene_group = darray_get(gene_groups, gg);
    darray_sort(gene_group, BAT_Free_Feature_tid_cmp);

    ffeat = (BAT_Free_Feature *) darray_get(gene_group, 0);
    gene = BAT_Gene_new();
    BAT_Gene_set_all(gene, ffeat->seqname, ffeat->source, ffeat->strand,
		     BAT_Free_Feature_get_gene_id(ffeat));

    n_fs = darray_size(gene_group);
    for (f = 0; f < n_fs;) {
      tx = BAT_Transcript_new();
      id = BAT_Util_copy_string(BAT_Free_Feature_get_transcript_id(ffeat));
      do {
	feat = BAT_Feature_new();
	BAT_Feature_set_all(feat, ffeat->type, ffeat->start, ffeat->end,
			    ffeat->score, ffeat->frame);
	BAT_Feature_set_comment(feat, BAT_Comment_copy(ffeat->comment));
	BAT_Transcript_add_feature(tx, feat);
	if (++f >= n_fs)
	  break;
	ffeat = darray_get(gene_group, f);
      }
      while (!strcmp(id, BAT_Free_Feature_get_transcript_id(ffeat)));
      BAT_Transcript_set_id(tx, id);
      BAT_Gene_add_transcript(gene, tx);
      free(id);
    }

    BAT_GeneTab_add_gene(gt, gene);
  }
  if (gene->_parent == NULL)
    BAT_Gene_delete(gene, 1);
  if (tx->_parent == NULL)
    BAT_Transcript_delete(tx, 1);
  darray_delete(gene_groups, 1);
  feat = NULL;

  return gt;
}
